home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / forth / pfe-0.000 / pfe-0 / pfe-0.9.13 / TUNING < prev   
Encoding:
Text File  |  1995-05-19  |  6.3 KB  |  194 lines

  1. TUNING THE PORTABLE FORTH ENVIRONMENT            -*- indented-text -*-
  2. #####################################
  3.  
  4. 1) Loop unrolling in the inner interpreter
  5. ==========================================
  6.  
  7. The most time critical piece of code in pfe is the inner interpreter,
  8. a tight loop calling all primitives compiled into a high-level
  9. definition. You find it in file support.c, function run_forth().
  10.  
  11. On some CPU's it significantly saves time when the code of the inner
  12. interpreter is unrolled several times without the need to jump back to
  13. the start of the loop after every primitive is executed. On other
  14. CPU's it doesn't help or even makes it slightly slower.
  15.  
  16. For example the benchmark-performance of pfe on a 486 is about 15%
  17. better with unrolled NEXT, while the performance on a Pentium becomes
  18. worse.
  19.  
  20. You'll have to try it, what is better on your machine. To enable the
  21. feature, add the following compiler option in Makefile:
  22.  
  23.      -DUNROLL_NEXT
  24.  
  25.  
  26. 2) Using global register variables
  27. ==================================
  28.  
  29. pfe is designed for best portability. This means it can be compiled
  30. with a variety of compilers on many systems. Obviously this prevented
  31. me from squeezing the last bit of performance out of any special
  32. system.
  33.  
  34. Fortunately there's a way to tune it up significantly with only little
  35. effort provided you have GNU-C at hand.
  36.  
  37. Let me explain: As most of you probably know, a Forth-interpreter
  38. traditionally contains a so-called virtual machine. pfe does. This
  39. virtual machine consists of several virtual registers and a basic set
  40. of operations. The virtual registers are:
  41.  
  42.     ip    an instruction pointer
  43.     sp    the data stack pointer
  44.     rp    the return stack pointer
  45.     w    an auxiliary register
  46.  
  47. in pfe there are additionally:
  48.  
  49.     lp    pointer to local variables
  50.     fp    floating point stack pointer
  51.  
  52. In a traditional assembler-based Forth implementation these virtual
  53. registers would be mapped to physical registers of the CPU at hand.
  54. How efficient such an implementation is depends heavily on how
  55. cleverly this mapping is done.
  56.  
  57. pfe has no other choice than to declare C-language global variables to
  58. represent these virtual registers. These variables are accessed *very*
  59. frequently.
  60.  
  61. Now GNU-C allows us to put global variables in registers! Obviously
  62. the number of registers in a CPU is limited and the use of registers
  63. by library functions and the compiler itself interferes.
  64.  
  65. In spite of these restrictions it is possible to find a niche even in
  66. an i386 where to place the two most important virtual registers
  67. resulting in a performance boost of about 50%. (Just one more detail
  68. that shows what a great job the GNU-C developers did.)
  69.  
  70.  
  71. If your system is one of those known by the config-script then all
  72. provisions to use global register variables are already taken.
  73. You can enable and disable the usage of global register variables in
  74. `src/makefile' by specifying the command line option '-DUSE_REGS'
  75. (default) or removing it.
  76.  
  77. If your system isn't known by the config script, then first make sure
  78. you have a stable port according to the instructions in the file
  79. `INSTALL'. Then read the next section to enable the usage of register
  80. variables on your system. If all works well please send me your
  81. changes.
  82.  
  83.  
  84. Warning:
  85.  
  86. current versions of gcc (<= 2.6.0) seem to compile incorrect code in
  87. very special situations when global register variables are used. This
  88. is reported and fixed in later gcc versions.
  89.  
  90. When you find something not working that worked in previous versions,
  91. then please check if it works again after recompiling pfe without
  92. -DUSE_REGS. Please inform me of such cases:
  93. duz@roxi.rz.fht-mannheim.de <Dirk Zoller>
  94.  
  95.  
  96. Choosing registers to use
  97. =========================
  98.  
  99. When you use global register variables in GNU-C then you have to
  100. explicitly state which machine register to use for the global variable
  101. to declare "register". The syntax is like this:
  102.  
  103.     register type variable_name asm ("machine register name");
  104.  
  105. instead of just
  106.  
  107.     type variable_name;
  108.  
  109. As far as I see choosing machine registers to use for global register
  110. variables is just a matter of trial and error.
  111.  
  112. First find out how registers are named on your machine. Not how the
  113. manufacturer names them but how gas, the GNU-assembler, names them.
  114. It's easy: simply use gcc to compile one of the C files with option
  115. -S.  I changed the `makefile' to allow this by simply `make core.s'.
  116.  
  117. Then look at `core.s': You don't have to know much of assembly
  118. language programming and even less of the particular CPU. All you are
  119. interested in is: what are the registers? In `core.s' search for the
  120. label `dupe_' i.e. the compiled function that does the work of the
  121. Forth word `DUP'.  The C-source for dupe is:
  122.  
  123.     Code (dupe)
  124.     {
  125.         --sp;
  126.         sp[0] = sp[1];
  127.     }
  128.  
  129.  
  130. On an RS/6000 (where you won't have to do this because I did it
  131. already) using gcc you'd find the following assembler lines generated
  132. for dupe_:
  133.  
  134. .dupe_:
  135.         l 11,LC..106(2)
  136.         l 9,0(11)
  137.         cal 0,-4(9)
  138.         st 0,0(11)
  139.         l 0,0(9)
  140.         st 0,-4(9)
  141.         br
  142.  
  143. Reading more of the generated assembler source allowed a guess that
  144.  - Gcc talks to the assembler about registers by their numbers only.
  145.  - Gcc never uses registers with numbers around 16 while the cpu seems
  146.    to have 32 such registers.
  147.  
  148. Next edit the file `src/virtual.h'. Add a system specific section of
  149. preprocessor definitions naming CPU registers to use for virtual
  150. machine registers like this:
  151.  
  152.     ...
  153.     #elif AIX3
  154.  
  155.     #  define REGIP "13"
  156.     #  define REGSP "14"
  157.     #  define REGRP "15"
  158.     #  define REGW  "16"
  159.     #  define REGLP "17"
  160.     #  define REGFP "18"
  161.  
  162.     #elif...
  163.  
  164. Ok, the full set needed a little more experimentation. Maybe start
  165. with only REGSP or REGIP.
  166.  
  167. After enabeling these declarations with the -DUSE_REGS command line
  168. option another `make core.s' yields the following translation for DUP:
  169.  
  170. .dupe_:
  171.     cal 14,-4(14)
  172.     l 0,4(14)
  173.     st 0,0(14)
  174.     br
  175.  
  176. Quite a difference!
  177.  
  178. If your CPU has different types of registers for data and for pointers
  179. then the pointers are needed in pfe. (On M68k the Ax not the Dx.)
  180.  
  181. If you don't have enough free registers in your CPU then serve the
  182. first virtual registers in the above list first. They are ordered by
  183. their importance.
  184.  
  185. Then do a `make new' with option -DUSE_REGS. If you get compiler
  186. errors and warnings about `spilled' or `clobbered' registers then
  187. change the mapping until it compiles quietly. There's a good chance
  188. that it still runs now and if it does it runs significantly faster
  189. than before.
  190.  
  191. Good luck!
  192.  
  193. Dirk
  194.